package com.talent.proxy.mysql.common.packets.c2s;

import java.nio.ByteBuffer;

import com.talent.aio.common.ChannelContext;
import com.talent.proxy.mysql.common.Capabilities;
import com.talent.proxy.mysql.common.MysqlExt;
import com.talent.proxy.mysql.common.MysqlPacket;
import com.talent.proxy.mysql.common.MysqlReturn;
import com.talent.proxy.mysql.common.utils.BufferUtil;

/**
 * <pre>
 * VERSION 4.1
 *  Bytes                        Name
 *  -----                        ----
 *  4                            capability_flags
 *  4                            max_packet_size
 *  1                            character_set
 *  23                           (filler) always 0x00...
 *  n (Null-Terminated String)   username
 *  n (Length Coded Binary)      auth-response scramble_buff (1 + x bytes)
 *  n (Null-Terminated String)   databasename (optional)
 * </pre>
 * <pre>
 * http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
 * </pre>
 * 
 */
public class AuthPacket extends MysqlPacket
{
	private static final byte[] FILLER = new byte[23];

	public long capabilityFlags;
	public long maxPacketSize;
	public int characterSet;
	public byte[] extra;
	public String user;
	public byte[] password;
	public String database;

	@Override
	public void decodeBody(ByteBuffer buffer, ChannelContext<MysqlExt, MysqlPacket, MysqlReturn> channelContext)
	{

		capabilityFlags = BufferUtil.readUB4(buffer);
		maxPacketSize = BufferUtil.readUB4(buffer);
		characterSet = (BufferUtil.read(buffer) & 0xff);
		int current = buffer.position();
		int len = (int) BufferUtil.readLength(buffer);
		if (len > 0 && len < FILLER.length)
		{
			byte[] ab = new byte[len];
			buffer.get(ab, 0, len);
			this.extra = ab;
		}
		buffer.position(current + FILLER.length);
		user = BufferUtil.readStringWithNull(buffer);
		password = BufferUtil.readBytesWithLength(buffer);
		if (((capabilityFlags & Capabilities.CLIENT_CONNECT_WITH_DB) != 0) && buffer.hasRemaining())
		{
			database = BufferUtil.readStringWithNull(buffer);
		}
	}

	@Override
	public ByteBuffer encode(ChannelContext<MysqlExt, MysqlPacket, MysqlReturn> channelContext)
	{
		int bodySize = bodySize();
		ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE + bodySize);
		BufferUtil.writeUB3(buffer, bodySize);

		buffer.put(seqId);
		BufferUtil.writeUB4(buffer, capabilityFlags);
		BufferUtil.writeUB4(buffer, maxPacketSize);
		buffer.put((byte) characterSet);
		buffer.put(FILLER);
		if (user == null)
		{
			buffer.put((byte) 0);
		} else
		{
			BufferUtil.writeWithNull(buffer, user.getBytes());
		}
		if (password == null)
		{
			buffer.put((byte) 0);
		} else
		{
			BufferUtil.writeWithLength(buffer, password);
		}
		if (database == null)
		{
			buffer.put((byte) 0);
		} else
		{
			BufferUtil.writeWithNull(buffer, database.getBytes());
		}
		return buffer;
	}

	@Override
	public int bodySize()
	{
		int size = 32;// 4+4+1+23;
		size += (user == null) ? 1 : user.length() + 1;
		size += (password == null) ? 1 : BufferUtil.getLength(password);
		size += (database == null) ? 1 : database.length() + 1;
		return size;
	}

	@Override
	protected String packetDesc()
	{
		return "MySQL Authentication Packet";
	}

	/** 
	 * @see com.talent.proxy.mysql.common.MysqlPacket#onReceived(com.talent.aio.common.ChannelContext)
	 * 
	 * @param channelContext
	 * @return
	 * @重写人: tanyaowu
	 * @重写时间: 2017年1月23日 下午1:54:57
	 * 
	 */
	@Override
	public MysqlReturn onReceived(ChannelContext<MysqlExt, MysqlPacket, MysqlReturn> channelContext)
	{
		//TODO 弄服务器端时再实现
		return null;
	}

	/**
	 * @return the capabilityFlags
	 */
	public long getCapabilityFlags()
	{
		return capabilityFlags;
	}

	/**
	 * @param capabilityFlags the capabilityFlags to set
	 */
	public void setCapabilityFlags(long capabilityFlags)
	{
		this.capabilityFlags = capabilityFlags;
	}

	/**
	 * @return the maxPacketSize
	 */
	public long getMaxPacketSize()
	{
		return maxPacketSize;
	}

	/**
	 * @param maxPacketSize the maxPacketSize to set
	 */
	public void setMaxPacketSize(long maxPacketSize)
	{
		this.maxPacketSize = maxPacketSize;
	}

	/**
	 * @return the characterSet
	 */
	public int getCharacterSet()
	{
		return characterSet;
	}

	/**
	 * @param characterSet the characterSet to set
	 */
	public void setCharacterSet(int characterSet)
	{
		this.characterSet = characterSet;
	}

	/**
	 * @return the extra
	 */
	public byte[] getExtra()
	{
		return extra;
	}

	/**
	 * @param extra the extra to set
	 */
	public void setExtra(byte[] extra)
	{
		this.extra = extra;
	}

	/**
	 * @return the user
	 */
	public String getUser()
	{
		return user;
	}

	/**
	 * @param user the user to set
	 */
	public void setUser(String user)
	{
		this.user = user;
	}

	/**
	 * @return the password
	 */
	public byte[] getPassword()
	{
		return password;
	}

	/**
	 * @param password the password to set
	 */
	public void setPassword(byte[] password)
	{
		this.password = password;
	}

	/**
	 * @return the database
	 */
	public String getDatabase()
	{
		return database;
	}

	/**
	 * @param database the database to set
	 */
	public void setDatabase(String database)
	{
		this.database = database;
	}

}
